/*
 *  QwertyKeyMapper.cpp
 *  Dictionary
 *
 *  Created by Rune Laugesen on 21/09/10.
 *  Copyright 2010 Copenhagen University. All rights reserved.
 *
 */

#include "QwertyKeyMapper.h"
#include <algorithm>
#include <sstream>

using namespace std;

QwertyKeyMapper::QwertyKeyMapper()
{
    BuildAlphabet();
}
// Build dictionary for calculating Levenshtein Distance
void QwertyKeyMapper::BuildAlphabet()
{
    _alphabet.insert ( pair<char, string>('.', ".") );
    _alphabet.insert ( pair<char, string>(',', ",") );
    _alphabet.insert ( pair<char, string>('!', "!") );
    _alphabet.insert ( pair<char, string>('?', "?") );
    _alphabet.insert ( pair<char, string>('a', "a  qsw") );
    _alphabet.insert ( pair<char, string>('b', " bhnv") );
    _alphabet.insert ( pair<char, string>('c', "  cfvx") );
    _alphabet.insert ( pair<char, string>('d', " defrs") );
    _alphabet.insert ( pair<char, string>('e', " de rsw") );
    _alphabet.insert ( pair<char, string>('f', "df grt") );
    _alphabet.insert ( pair<char, string>('g', " f ght y") );
    _alphabet.insert ( pair<char, string>('h', "   ghjuy") );
    _alphabet.insert ( pair<char, string>('i', " ijko u") );
    _alphabet.insert ( pair<char, string>('j', "hijku") );
    _alphabet.insert ( pair<char, string>('k', " ijklo") );
    _alphabet.insert ( pair<char, string>('l', "   klop") );
    _alphabet.insert ( pair<char, string>('m', "   klmn") );
    _alphabet.insert ( pair<char, string>('n', " bj mn") );
    _alphabet.insert ( pair<char, string>('o', " i klop") );
    _alphabet.insert ( pair<char, string>('p', "    lop") );
    _alphabet.insert ( pair<char, string>('q', "a q w") );
    _alphabet.insert ( pair<char, string>('r', " defrt") );
    _alphabet.insert ( pair<char, string>('s', "ade  sw") );
    _alphabet.insert ( pair<char, string>('t', "  fgrt y") );
    _alphabet.insert ( pair<char, string>('u', "hij   uy") );
    _alphabet.insert ( pair<char, string>('v', " bcgv") );
    _alphabet.insert ( pair<char, string>('w', "a eq sw") );
    _alphabet.insert ( pair<char, string>('x', "  cd xz") );
    _alphabet.insert ( pair<char, string>('y', "   ghtuy") );
    _alphabet.insert ( pair<char, string>('z', "    sxz") );
    _alphabet.insert ( pair<char, string>('0', "        90") );
    _alphabet.insert ( pair<char, string>('1', "12") );
    _alphabet.insert ( pair<char, string>('2', "123") );
    _alphabet.insert ( pair<char, string>('3', " 234") );
    _alphabet.insert ( pair<char, string>('4', "  345") );
    _alphabet.insert ( pair<char, string>('5', "   456") );
    _alphabet.insert ( pair<char, string>('6', "    567") );
    _alphabet.insert ( pair<char, string>('7', "     678") );
    _alphabet.insert ( pair<char, string>('8', "      789") );
    _alphabet.insert ( pair<char, string>('9', "       890") );
}

void QwertyKeyMapper::MapDictionary()
{
    /*
    for (vector<string>::iterator it = _dictionary.begin(); it != _dictionary.end(); it++)
    {
        string word = (*it);//_bktree.WordToKeys((*it));
        string keys = _bktree.WordToKeys((*it));//(*it);//StringToKeys(word);
        _mappedDictionary.insert(pair<string, string>(word, keys));
    }
    */
    _bktree.BuildDictionary(_dictionary);

}

//Is a keystroke ubiquitous or should typos be rulled out?
//How can typos be tested? Test the model with hamming distance and type-alphabet (_alphabet), and compare the results
//If a word is not found in the or if the list is less than n words add nextbestmatch(word, n);
//string keys = StringToKeys(word);
// when should we start predicting, at how many chars - 2 less that word length?
vector<string> QwertyKeyMapper::GetMappings(string word)
{
    vector<string> mappings;
    //pair<multimap<string, string>::iterator, multimap<string, string>::iterator> it;
    
    //TODO - change _distance to a factor
    double distfactor = 1;
    int distance = round(distfactor * word.length());
    
    //string searchkey = word.substr(0, word.length() < 5 ? word.length() : 4);
    
    //string searchkey = word.substr(0, word.length() < 4 ? word.length() : word.length()-2);
    
    //map<string, string>::const_iterator it = _mappedDictionary.lower_bound(searchkey);
    
    //only use BKTree not lower_bound
    //skip words that are shorter than saerchkey
    
    //while (it != _mappedDictionary.end())
    //{
    //    const string& key = it->second;
    //    const string& searchword = it->first;
        
    //    if (searchword.size() > word.size() + 2)
    //    {
    //        it++;
    //        continue;
    //    }

    //    if (searchword.compare(0, searchkey.size(), searchkey) == 0)
    //    {
    //auto words = _bktree.FindWithin(_bktree.WordToKeys(word), distance);//.Search(word, distance);
    auto words = _bktree.Search(word, distance);
            int i = 0;
            for (auto itword = words.begin(); itword != words.end(); ++itword)
            {
                if (i == 5)
                    break;
                
                mappings.push_back((*itword).second);
                i++;
            }
    //    }

    //    it++;
    //}

    return mappings;
}

